/****************************************************************************/
/* This file is part of FreeFem++.                                          */
/*                                                                          */
/* FreeFem++ is free software: you can redistribute it and/or modify        */
/* it under the terms of the GNU Lesser General Public License as           */
/* published by the Free Software Foundation, either version 3 of           */
/* the License, or (at your option) any later version.                      */
/*                                                                          */
/* FreeFem++ is distributed in the hope that it will be useful,             */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of           */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
/* GNU Lesser General Public License for more details.                      */
/*                                                                          */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with FreeFem++. If not, see <http://www.gnu.org/licenses/>.        */
/****************************************************************************/
// SUMMARY : Example C++ function "CppModTemplate" dynamically loaded into "load.edp"
// LICENSE : LGPLv3
// ORG     : LJLL Universite Pierre et Marie Curie, Paris, FRANCE
// AUTHORS : ...
// E-MAIL  : ...

#include "ff++.hpp"
using namespace Fem2D;	// see src/femlib/RNM.hpp

class myType {
	public:
		string *nom;
		myType (char *nn) {cout << " nn = " << nn << endl;}

		double x (double u, double v) const {return u + v;}

		void init () {cout << " init myTpe \n"; nom = 0;}	// initialization of the pointer

		void destroy () {cout << " destroy de la variable associe \n"; delete nom; nom = 0;}
};

class myType_uv {
	public:
		myType *mt;
		double u, v;
		myType_uv (myType *mmt, double uu, double vv): mt(mmt), u(uu), v(vv) {}
};

// le vrai constructeur est la
myType*init_MyType (myType *const &a, string *const &s) {
	a->nom = new string(*s);
	cout << " build MyType " << *a->nom << endl;
	return NULL;// return value never used for now (13.1)
}

myType_uv set_myType_uv (myType *const &mt, const double &u, const double &v)
{return myType_uv(mt, u, v);}

double get_myType_uv_x (const myType_uv &muv) {
	return muv.mt->x(muv.u, muv.v);
}

R3*get_myType_uv_N (const myType_uv &muv) {
	static R3 r;

	r = R3(muv.mt->x(muv.u, muv.v), 0., 0.);
	return &r;
}

// Add the function name to the freefem++ table
/*  class Init { public:
 * Init();
 * };
 * $1 */
static void Load_Init () {
	Dcl_Type<myType *>(InitP<myType>, Destroy<myType> );// declare deux nouveau type pour freefem++  un pointeur et
	Dcl_Type<myType_uv>();
	// Dcl_Type<R3>();
	// cast d'un ** en *
	// atype<myType**>()->AddCast( new E_F1_funcT<myType*,myType **>(UnRef<myType*>));

	zzzfff->Add("myType", atype<myType *>());	// ajoute le type myType a freefem++
	// constructeur  d'un type myType  dans freefem
	TheOperators->Add("<-",
	                  new OneOperator2_<myType *, myType *, string *>(&init_MyType));
	// dans ff++
	// myType ff("qsdlqdjlqsjdlkq");
	// ajoute la fonction  myType* (u,v) cree le type myType_uv
	// ff(0.1,0.6).x
	// deux etapes
	// 1)  ff(u,v) -> myType_uv
	// ajoute la methode x sur myType_uv   ff(u,v).x
	// ajoute des fonction sur myType_uv
	// 1)

	atype<myType *>()->Add("(", "", new OneOperator3_<myType_uv, myType *, double, double>(set_myType_uv));

	Add<myType_uv>("x", ".", new OneOperator1_<double, myType_uv>(get_myType_uv_x));
	Add<myType_uv>("N", ".", new OneOperator1_<R3 *, myType_uv>(get_myType_uv_N));
}

LOADFUNC(Load_Init)

